#pragma once

#include <iostream>
#include <sys/epoll.h>

// 虚基类 Poll 的声明被注释掉了，原本可能是为了作为 Epoll 和未来可能实现的 Select 类的基类，
// 以提供一个统一的接口进行I/O多路复用操作。但目前并未实现。

class Epoll
{
    // gnum 是 epoll_create 函数中的最大监听文件描述符数量，默认值为128。
    const static int gnum = 128;

    // gtimeout 是 epoll_wait 函数的默认超时时间，单位为毫秒，默认值为5000毫秒。
    const static int gtimeout = 5000;

public:
    // Epoll 类的构造函数，初始化超时时间为默认或提供的值。
    Epoll(int timeout = gtimeout) : _timeout(timeout)
    {
    }

    // 创建一个 epoll 文件描述符，参数 gnum 指定了可以同时监控的最大文件描述符数量。
    // 如果创建失败，则程序退出。
    void CreateEpoll()
    {
        _epfd = epoll_create(gnum);
        if (_epfd < 0)
            exit(5);
    }

    // 从 epoll 集合中删除指定的文件描述符 sock。
    bool DelFromEpoll(int sock)
    {
        int n = epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
        return n == 0;
    }

    // 修改 epoll 集合中指定文件描述符 sock 的事件监听类型，添加 EPOLLET (边缘触发) 标志。
    bool CtrlEpoll(int sock, uint32_t events)
    {
        events |= EPOLLET;
        struct epoll_event ev;
        ev.events = events;
        ev.data.fd = sock;
        int n = epoll_ctl(_epfd, EPOLL_CTL_MOD, sock, &ev);
        return n == 0;
    }

    // 向 epoll 集合中添加新的文件描述符 sock，并指定其事件监听类型。
    bool AddSockToEpoll(int sock, uint32_t events)
    {
        struct epoll_event ev;
        ev.events = events;
        ev.data.fd = sock;
        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, sock, &ev);
        return n == 0;
    }

    // 等待 epoll 集合中的事件发生，revs[] 用于接收发生的事件，num 指定了revs[]的大小，
    // _timeout 是等待超时时间（毫秒）。返回实际发生的事件数量。
    int WaitEpoll(struct epoll_event revs[], int num)
    {
        return epoll_wait(_epfd, revs, num, _timeout);
    }

    // 析构函数，当前没有特定的操作。
    ~Epoll()
    {
    }

private:
    // _epfd 是由 epoll_create 创建的 epoll 文件描述符。
    int _epfd;

    // _timeout 是 epoll_wait 调用时的超时时间。
    int _timeout;
};